﻿using System.Net;
using System.Text.Json.Serialization;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Caching.Distributed;
using WT.OpenIddict.Application.Email;
using WT.OpenIddict.Domain;
using WT.OpenIddict.Domain.Roles;
using WT.OpenIddict.Domain.Services.Exceptions;
using WT.OpenIddict.Domain.Shared.User;
using WT.OpenIddict.Domain.Shared.VertifyCodeUtils;
using WT.OpenIddict.Domain.User;

namespace WT.OpenIddict.WebApi.Controllers;

public class LoginController : ControllerBase
{
    private const string userRole = "普通用户";

    private readonly IDistributedCache _distributedCache;

    private readonly RoleManager<RoleDetails> _roleManager;

    private readonly SendEmailManager _sendEmailManager;

    private readonly SignInManager<UserDetails> _signInManager;
    private readonly UserManager<UserDetails> _userManager;

    public LoginController(UserManager<UserDetails> userManager, SignInManager<UserDetails> signInManager,
        IConfiguration configuration, RoleManager<RoleDetails> roleManager, IDistributedCache distributedCache,
        SendEmailManager sendEmailManager)
    {
        _userManager = userManager;
        _signInManager = signInManager;
        Configuration = configuration;
        _roleManager = roleManager;
        _distributedCache = distributedCache;
        _sendEmailManager = sendEmailManager;
    }

    public IConfiguration Configuration { get; set; }

    [HttpPost("~/account/login")]
    public async Task<IActionResult> Login([FromBody] LoginRequestModel model)
    {
        var user = await _userManager.FindByNameAsync(model.Username);
        if (user == null) user = await _userManager.FindByEmailAsync(model.Username);
        if (user == null) throw new ForbiddenException("用户不存在", "user_notfound");
        if (!await _userManager.CheckPasswordAsync(user, model.Password))
            throw new ForbiddenException("用户名或密码错误", "invalid_credentials");
        //判断是否封禁
        if (user.Banned) throw new ForbiddenException("账号被封禁，请联系管理员", "invalid_credentials");

        // 设置身份验证 Cookie
        await HttpContext.SignInAsync(
            "CustomCookie",
            await _signInManager.CreateUserPrincipalAsync(user),
            new AuthenticationProperties
            {
                IsPersistent = true,
                ExpiresUtc = DateTimeOffset.UtcNow.AddDays(7)
            });

        // 构造重定向 URL 及查询参数
        var redirectUrl = "/connect/authorize";
        var queryParams = new Dictionary<string, string>
        {
            // 将 model 的属性添加到查询参数中（排除敏感字段）
            { "response_type", model.ResponseType },
            { "client_id", model.ClientId },
            { "redirect_uri", model.RedirectUri },
            { "scope", model.Scope },
            { "state", model.State },
            { "code_challenge", model.CodeChallenge },
            { "code_challenge_method", model.CodeChallengeMethod }
        };

        // 构造完整的查询字符串
        var queryString = string.Join("&", queryParams
            .Select(kvp => $"{WebUtility.UrlEncode(kvp.Key)}={WebUtility.UrlEncode(kvp.Value)}"));

        // 拼接最终的重定向 URL
        var fullUrl = $"{redirectUrl}?{queryString}";
        // 返回重定向
        //是否https,是的话不需要再加端口,要配置nginx转发
        string RedirectUri;
        if (int.Parse(Configuration["Redirect:IsHttps"]) == 1)
            RedirectUri = $"{Configuration["Redirect:BaseAddress"]}{Configuration["PathBase"]}" + fullUrl;
        else
            RedirectUri = $"{Configuration["Redirect:BaseAddress"]}:{Configuration["Redirect:Port"]}" + fullUrl;
        return Ok(new { Success = true, RedirectUri });
    }

    [HttpPost("~/account/registe")]
    public async Task Register([FromBody] RegisterRequestModel input)
    {
        var user = await _userManager.FindByNameAsync(input.UserName);
        if (user == null) user = await _userManager.FindByEmailAsync(input.UserName);
        if (user != null) throw new UserFriendlyException("用户名已存在");
        var success = await _userManager.CreateAsync(new UserDetails
            {
                UserName = input.UserName,
                Email = input.Email,
                NickName = input.NickName,
                RegisterTime = DateTime.Now,
                Sex = input.Gender == 1 ? EnumSexy.Male : EnumSexy.FeMale
            }, input.Password
        );
        if (!success.Succeeded) throw new UserFriendlyException(success.Errors.FirstOrDefault().Description);
        var role = await _roleManager.FindByNameAsync(userRole);
        var newUser = await _userManager.FindByNameAsync(input.UserName);
        if (role != null) await _userManager.AddToRoleAsync(newUser, role.Name);
        //这里是给用户一个默认头像，自行修改实现
        // var defalutUserAvatar = await _fileRepo.FindAsync(it => it.BusinessType == UserDefaultConst.User_BussinessType);
        // var newAvatar = defalutUserAvatar.DeepCopy();
        // newAvatar.Id = Guid.Empty;
        // newAvatar.BusinessId = newUser.Id.ToString();
        // newAvatar.BusinessType = OpenIddictConst.UserBusinessType;
        // await _fileRepo.InsertAsync(newAvatar);
    }

    [HttpGet("~/account/clear")]
    public async Task ClearToken()
    {
        // 假设你的 Cookie 名为 "MyCookie"
        Response.Cookies.Append("CustomCookie", "", new CookieOptions
        {
            Expires = DateTimeOffset.UtcNow.AddDays(-1), // 设为过去时间
            Path = "/"
        });
        await Task.CompletedTask;
    }

    [HttpPost("~/account/send-code/{email}")]
    public async Task SendVertifyCode(string email)
    {
        var user = await _userManager.FindByEmailAsync(email);
        if (user == null) throw new InvalidOperationException("用户不存在,请检查您的邮箱");
        await _distributedCache.RemoveAsync(string.Format(OpenIddictConst.RedisVerifyCodeKey, email));
        // 1. 生成6位字母数字验证码
        var code = VertifyCodeGenerator.GenerateCode(6);
        await _sendEmailManager.SendVertifyCodeEmail(email, code);
        // 2. 存入Redis，key可以用邮箱，value为验证码，5分钟过期
        var options = new DistributedCacheEntryOptions
        {
            AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(5)
        };
        await _distributedCache.SetStringAsync(string.Format(OpenIddictConst.RedisVerifyCodeKey, email), code, options);
    }

    [HttpPost("~/account/vertify-code")]
    public async Task<ResetTokenDto> VertifyCode([FromBody] VertifyCodeRequest request)
    {
        var resetTokenDto = new ResetTokenDto();
        var user = await _userManager.FindByEmailAsync(request.Email);
        if (user == null) throw new InvalidOperationException("用户不存在,请检查您的邮箱");
        var code = await _distributedCache.GetStringAsync(string.Format(OpenIddictConst.RedisVerifyCodeKey,
            request.Email));
        if (code == null) throw new UserFriendlyException("验证码不存在或已过期");
        if (code.ToLowerInvariant() != request.Code.ToLowerInvariant()) throw new UserFriendlyException("验证码错误");
        resetTokenDto.Token = await _userManager.GeneratePasswordResetTokenAsync(user);
        return resetTokenDto;
    }


    [HttpPut("~/account/reset-password")]
    public async Task ResetPassword([FromBody] ResetPasswordRequest request)
    {
        var user = await _userManager.FindByEmailAsync(request.Email);
        if (user == null) throw new InvalidOperationException("用户不存在,请检查您的邮箱");
        var result = await _userManager.ResetPasswordAsync(user, request.ResetToken, request.NewPassword);
        if (!result.Succeeded) throw new UserFriendlyException(result.Errors.FirstOrDefault().Description);
    }

    public class ResetTokenDto
    {
        public string Token { get; set; }
    }

    public class ResetPasswordRequest
    {
        public string Email { get; set; }

        public string NewPassword { get; set; }

        public string ResetToken { get; set; }
    }


    public class VertifyCodeRequest
    {
        public string Email { get; set; }

        public string Code { get; set; }
    }


    public class RegisterRequestModel
    {
        public string UserName { get; set; }
        public string Password { get; set; }

        public string NickName { get; set; }

        public string Email { get; set; }

        public string PhoneNumber { get; set; }

        public int Gender { get; set; }
    }


    public class LoginRequestModel
    {
        public string Username { get; set; }
        public string Password { get; set; }

        /// <summary>
        ///     响应类型（对应 response_type）
        /// </summary>
        [JsonPropertyName("response_type")]
        public string ResponseType { get; set; }

        /// <summary>
        ///     客户端ID（对应 client_id）
        /// </summary>
        [JsonPropertyName("client_id")]
        public string ClientId { get; set; }

        /// <summary>
        ///     回调地址（对应 redirect_uri）
        /// </summary>
        [JsonPropertyName("redirect_uri")]
        public string RedirectUri { get; set; }

        /// <summary>
        ///     请求作用域（对应 scope）
        /// </summary>

        public string Scope { get; set; }

        /// <summary>
        ///     状态参数（对应 state）
        /// </summary>
        public string State { get; set; }

        /// <summary>
        ///     PKCE 挑战码（对应 code_challenge）
        /// </summary>
        [JsonPropertyName("code_challenge")]
        public string CodeChallenge { get; set; }

        /// <summary>
        ///     挑战码生成方法（对应 code_challenge_method）
        /// </summary>
        [JsonPropertyName("code_challenge_method")]
        public string CodeChallengeMethod { get; set; }
    }
}